#ifndef __SHELL_H
#define __SHELL_H

#include <iostream>
#include <cstring>
#include <stdio.h>

#define SHELL_VERSION       "V1.0.1"    //当前shell版本
#define EXEC_IDENTIFY       "AA55"      //@C 执行命令时需校验的字串头

#define MARK_1              "@"         //匹配 标识头
#define MARK_2              "="         //匹配 标识赋值
#define MAX_KEY_LEN         4           //最大键长度
#define MAX_VAL_LEN         25          //最大值长度
#define MAX_COLLECT_LEN     60          //采集缓存区长度
#define NODE_GROUP_NUM      30          //节点数 30*16=480字节
#define SHELL_BUF_SIZE      512         //缓存长度
#define DEFAULT_BAUD_RATE   115200      //默认波特率

typedef struct _node{
    char *key;
    char *val;
    struct _node* next=NULL;
    struct _node* previous=NULL;
}cmd_node;

typedef struct _cmd_handle{
    const char* cmd;
    void(*func)(cmd_node* buf);
}cmd_handle;

typedef struct _execute_handle{
    const char* cmd;
    void(*func)(char* data,int len);
}execute_handle;

typedef int (*send_handle)(uint8_t* data,int len);      //上报函数结构

typedef struct _variable{
    int recv_resp;                          //是否接收应答
    uint32_t baud_rate;                     //串口默认波特率
    char shell_buf[SHELL_BUF_SIZE];         //shell缓存区
    int shell_len;                          //使用的缓存字节数
    int node_num;                           //使用的节点数
    int wait_loop;                          //遇到M 等待L 开始循环
    int echo_cmd;                           //命令是否回传
    int shell_loop;                         //脚本无线循环
    int upload_per;                         //上报周期
    int inform_format;                      //采集数据格式
    cmd_node node_group[NODE_GROUP_NUM];    //双链表容器    注意：数组下标排列顺序是错的，按链表指针顺序
    cmd_node *head,*tail;                   //头节点，尾节点
    send_handle send_data;                  //用户发送函数，因为要实现输出控制
    uint8_t collect_buf[MAX_COLLECT_LEN];   //设备采集数据
    int collect_len;                        //当前采集数据长度
    uint32_t packet_num;                    //包序号
    int cut_sta,cut_size;                   //cut起始 cut长度
    execute_handle* execute_handle_group;   //用户命令执行函数（ @C 和 @O ）
    int execute_handle_len;                 //用户函数数量
}shell_variable;

extern shell_variable shell_var;

void shell_init();                                  //初始化shell环境
int register_inform(send_handle f);                 //注册发送函数
int register_execute(execute_handle* group,int handle_size);     //注册用户执行函数
int insert_tail(cmd_node* node);                    //尾插节点
int insert_pos(int pos, cmd_node* node);            //指定位置插入节点
int get_node_pos(cmd_node* node,int num);           //获取节点索引（链表顺序）
int unpack(char* buf,int buf_len);                  //拆包，生成节点
int search_cmd_handle(cmd_node* node);              //调用对应函数
int execute(cmd_node* handle,int len);              //执行shell命令
void set_node_num(uint16_t new_num);                //设置节点数
uint16_t get_node_num();                            //获取节点数
void inform();                                      //上报采集数据，并清空采集缓存区
void write_collect(uint8_t* data,int length,int format); //写数据到采集，format如果为1 强行转化 hex => str : 0x01 => 3031 => "01"
cmd_node* get_node_bypos(int pos);                  //返回节点指针，通过链表顺序
cmd_node* get_node_bykey(char* key);                //返回节点指针，通过key
void clean_shell_buf();                             //清空shell缓存区
void clean_node_list();                             //清空所有节点
void clean_collect();                               //清空采集数据
int drop_node_bypos(int pos);                       //删除节点（通过链表顺序）
int drop_node_bynode(cmd_node* node);               //删除节点（通过节点指针）
void show_node(cmd_node* node);                     //打印所有节点
void var_restore();                                 //按文档，脚本执行后，需要恢复部分参数
int search_execute_handle(char* data,int len);      //搜索用户执行函数，回调
void recycle();
#endif
